package org.fioma.tree.bytes;

import java.io.BufferedWriter;
import java.io.IOException;

import org.fioma.tree.Node;
import org.fioma.tree.SimpleInternalNode;

public abstract class SimpleInternalNodeBytes<I extends SimpleInternalNodeBytes<I, F>, F extends SimpleLeafBytes<I, F>> extends
		SimpleInternalNode<byte[], I, F> {

	public SimpleInternalNodeBytes(I parent, byte[] label) {
		this.parent = parent;
		this.label = label;
	}

	// add a new node in the position pos of the current label with label word.
	// The letter in the position pos of the current label will belong to the current label Node
	@Override
	public F addNode(byte pos, byte[] word) {
		return Tools.addNodeBytes(this, pos, word);
	}

	@Override
	public short getLengthLabel() {
		return label[0];
	}

	@Override
	public F addWord(byte[] word) {
		if (word != null && word.length > 0 && word[0] > 0) {
			byte firstLetter = (byte) (word[1] & 0x03);
			Node<byte[], I, F> nextNode = this.nextNode(firstLetter);
			if (nextNode == null) {
				F ret = this.createLeaf(word);
				this.setChild(ret, firstLetter);
				return ret;
			} else {
				byte[] nextWord = (byte[]) nextNode.getLabel();
				short mismatch = Tools.compare(word, nextWord);
				if (mismatch >= 0 && mismatch < word[0]) {
					// word must be splitted
					byte[] wordSplitted = Tools.substring(word, mismatch);
					if (mismatch == nextWord[0]) {
						// next word will not be splitted and a new node will not be created in this section
						return nextNode.addWord(wordSplitted);
					} else {
						// new internal node must be created
						return nextNode.addNode((byte) mismatch, wordSplitted);
					}
				} else {
					// word already in the tree
					return null;
				}
			}
		} else {
			return null;
		}
	}

//	public int addSuffix(byte[] suffix) {
//		if (suffix != null && suffix[0] > 0) {
//			byte firstLetter = (byte) (suffix[1] & 0x03);
//			Node<byte[]> nextNode = (Node<byte[]>) this.nextNode(firstLetter);
//			if (nextNode == null) {
//				this.setChild(new LeafBytes(this, suffix), firstLetter);
//				return 2;
//			} else {
//				byte[] nextWord = (byte[]) nextNode.getLabel();
//				short mismatch = Tools.compare(suffix, nextWord);
//				if (mismatch >= 0 && mismatch < suffix[0]) {
//					// word must be splitted
//					byte[][] wordSplitted = Tools.splitWord(suffix, mismatch);
//					if (mismatch == nextWord[0]) {
//						// next word will not be splitted and a new node will not be created in this section
//						return nextNode.addSuffix(wordSplitted[1]);
//					} else {
//						// new internal node must be created
//						nextNode.addNode((byte) mismatch, wordSplitted[1]);
//						return 2;
//					}
//				} else {
//					return 3;
//				}
//			}
//		}
//		return 3;
//	}
//

	@Override
	public void printWords(BufferedWriter bw, byte[] prefix) throws IOException {
		byte[] newPrefix = Tools.joinWords(prefix, label);
		for (Node node : nodes) {
			if (node != null) {
				node.printWords(bw, newPrefix);
			}
		}

	}

	@Override
	public boolean find(byte[] word) {
		if (word == null || word.length == 0 || word[0] == 0) {
			return true;
		} else {
			byte firstLetter = (byte) (word[1] & 0x03);
			Node<byte[], I, F> nextNode = this.nextNode(firstLetter);
			if (nextNode == null) {
				return false;
			} else {
				byte[] nextWord = (byte[]) nextNode.getLabel();
				short mismatch = Tools.compare(word, nextWord);
				if (mismatch >= 0 && mismatch < word[0]) {
					// word must be splitted
					byte[][] wordSplitted = Tools.splitWord(word, mismatch);
					if (mismatch == nextWord[0]) {
						// next word will not be splitted and a new node will not be created in this section
						return nextNode.find(wordSplitted[1]);
					} else {
						// new internal node must be created
						return false;
					}
				} else {
					return true;
				}
			}
		}
	}

	@Override
	public Node<byte[], I, F> findExistentNode(byte[] word) {
		if (word == null || word.length == 0 || word[0] == 0) {
			return this;
		} else {
			byte firstLetter = (byte) (word[1] & 0x03);
			Node<byte[], I, F> nextNode = this.nextNode(firstLetter);
			if (nextNode == null) {
				return null;
			} else {
				byte[] nextWord = nextNode.getLabel();
				short mismatch = Tools.compare(word, nextWord);
				if (mismatch < 0) {
					return nextNode;
				} else {
					if (mismatch < word[0] && mismatch == nextWord[0]) {
						return nextNode.findExistentNode(Tools.substring(word, mismatch));
					} else {
						return null;
					}

				}
			}
		}
	}
//	@Override
//	public int addToSuffixTree(SuffixNode tree, byte[] prefix, int phase) {
//		byte[] newPrefix = Tools.joinWords(prefix, label);
//		for (Node node : nodes) {
//			if (node != null) {
//				node.addToSuffixTree(tree, newPrefix, phase);
//				phase = newPrefix[0];
//			}
//		}
//		return 0;
//	}
}
